home *** CD-ROM | disk | FTP | other *** search
- ; /*
- ; ##########################################################################
- ; #### ####
- ; #### TurboDevice - A resident RAM disk for the Amiga ####
- ; #### ================================================= ####
- ; #### ####
- ; #### TurboDev.asm ####
- ; #### ####
- ; #### Version 1.00os -- May 04, 1991 ####
- ; #### ####
- ; #### Copyright (C) 1990 Thomas Dreibholz ####
- ; #### 1991 Molbachweg 7 ####
- ; #### 51674 Wiehl/Germany ####
- ; #### EMail: Dreibholz@bigfoot.com ####
- ; #### WWW: http://www.bigfoot.com/~dreibholz ####
- ; #### ####
- ; ##########################################################################
- ; */
- ;/***************************************************************************
- ; * *
- ; * This program is free software; you can redistribute it and/or modify *
- ; * it under the terms of the GNU General Public License as published by *
- ; * the Free Software Foundation; either version 2 of the License, or *
- ; * (at your option) any later version. *
- ; * *
- ; ***************************************************************************/
-
- ; #######################################################
- ; ## ##
- ; ## Das Turbo-Drive-System ##
- ; ## ====================== ##
- ; ## ##
- ; ## Entwicklungszeit: 21 Monate ##
- ; ## Fertigstellung: 4. Mai 1991 18:10:18 Uhr ##
- ; ## Aktuelle Version: 29. Jun 1991 ##
- ; ## ##
- ; #######################################################
-
- ; Diese Dateien werden vom Assembler eingebunden
-
- include "exec/types.i"
- include "exec/initializers.i"
- include "exec/libraries.i"
- include "exec/lists.i"
- include "exec/nodes.i"
- include "exec/resident.i"
- include "exec/alerts.i"
- include "exec/ables.i"
- include "exec/devices.i"
- include "exec/io.i"
- include "exec/memory.i"
- include "exec/errors.i"
- include "libraries/dos.i"
- include "libraries/dosextens.i"
-
- ; Es folgen 2 Makros zum Aufrufen von Library-Funktionen
-
- CALLSYS MACRO
- jsr _LVO%1(a6)
- endm
- LINKSYS MACRO
- move.l a6,-(a7)
- move.l %2,a6
- jsr _LVO%1(a6)
- move.l (a7)+,a6
- endm
-
- ; XLIB wird zum Einbinden der Library-Offsets benutzt
-
- XLIB MACRO
- XREF _LVO%1
- endm
-
- ; TURBO_NUMUNITS gibt die Anzahl der verfügbaren Units an.
- ; Das turbo.device stellt 50 Verwaltungseinheiten (Units)
- ; zur Verfügung.
-
- TURBO_NUMUNITS EQU 50
-
- ; TurboDev ist die Device-Struktur die das Device verwaltet.
- ; in fd_Units befinden sich Zeiger auf die einzelnen Unit-
- ; -Strukturen.
-
- STRUCTURE TurboDev,LIB_SIZE
- ULONG td_SysLib ; exec.library
- ULONG td_DosLib ; dos.library
- ULONG td_SegList ; Segmentliste
- ULONG td_Resident ; Resident (nicht immer belegt!)
- UBYTE td_Flags ; Flags
- UBYTE td_DriveNum ; nächste Namennummer
- STRUCT td_Units,TURBO_NUMUNITS*4 ; Zeiger auf Units
- LABEL TurboDev_SIZE
-
- ; TurboDevMsg wird für den Unit-Prozeß benötigt.
-
- STRUCTURE TurboDevMsg,MN_SIZE
- APTR tdm_Device ; Zeiger auf Device
- APTR tdm_Unit ; Zeiger auf Unit
- LABEL TurboDevMsg_SIZE
-
- ; TurboDevUnit ist die Struktur zur Verwaltung der einzelnen
- ; Verwaltungseinheiten (Units).
-
- STRUCTURE TurboDevUnit,UNIT_SIZE
- UBYTE tdu_UnitNum ; Unit-Nummer
- UBYTE tdu_pad ; Füllbyte
- STRUCT tdu_Msg,TurboDevMsg_SIZE ; TurboDevMsg
- APTR tdu_Process ; Unit-Prozeß
- LONG tdu_LastComm ; Letztes Kommando für LastComm
- LONG tdu_Size ; Kapazität des Laufwerks (Bytes)
- ULONG tdu_NumTracks ; Anzahl der Tracks
- ULONG tdu_Position ; Lese/Schreibkopf-Position
- APTR tdu_Memory ; Zeiger auf den Speicherbereich
- LABEL TurboDevUnit_SIZE
-
- ; Mit den Funktionen Stop und Start läßt sich die Verarbeitung
- ; anhalten. In UNIT_FLAGS wird FDUF_STOPPED gesetzt.
-
- BITDEF TDU,STOPPED,2 ; Stop-Bit
-
- TURBONAME MACRO ; Name des Turbo-Devices
- dc.b 'turbo.device',0
- endm
-
- ; Diese Funktionen werden vom Linker eingebunden.
-
- XREF _GetMemory ; Funktion zum Organisieren des Speichers
- XREF _GetDriveSize ; Funktion zur Kapazitätsberechnung
- XLIB OpenLibrary ; Library öffnen
- XLIB CloseLibrary ; Library schließen
- XLIB Alert ; Guru ausgeben
- XLIB FreeMem ; Speicher freigeben
- XLIB Remove ; Node entfernen
- XLIB FindTask ; Task suchen
- XLIB AllocMem ; Speicher belegen
- XLIB CreateProc ; Prozeß erzeugen
- XLIB PutMsg ; Message senden
- XLIB RemTask ; Task entfernen
- XLIB ReplyMsg ; Message zurücksenden
- XLIB Signal ; Signale setzen
- XLIB GetMsg ; Message erwarten
- XLIB Wait ; Auf Signal warten
- XLIB WaitPort ; Auf Message warten
- XLIB AllocSignal ; Signal belegen
- XLIB SetTaskPri ; Taskpriorität setzen
- XLIB Permit ; Multitasking zulassen
-
- INT_ABLES
-
- ; Damit das Device, wenn er versehentlich gestartet wurde,
- ; keinen Absturz erzeugt, wird das Device in START wieder
- ; beendet.
-
- START:
- move.l #$20000,d0 ; $20000 in d0
- 1$: ; Schleife
- move.w #$0F00,$DFF180 ; Rot in Farbregister 0
- subq.l #1,d0 ; 1 subtrahieren
- tst.l d0 ; ist d0=0 ?
- bne 1$ ; Nein, dann zu 1$
- moveq.l #0,d0 ; Keine Fehlermeldung
- rts ; Rücksprung
-
- PRIORITY: EQU 50 ; Priorität
- VERSION: EQU 35 ; Version
- REVISION: EQU 0 ; Revision
-
- ; Hier beginnt die Resident-Struktur für das Device
-
- InitTable:
- dc.w RTC_MATCHWORD ; Code für Resident
- dc.l InitTable ; Zeiger auf Anfang
- dc.l EndCode ; Zeiger auf Ende
- dc.b RTF_AUTOINIT ; Flag für autom. Installation
- dc.b VERSION ; Version
- dc.b NT_DEVICE ; Flag für Device
- dc.b PRIORITY ; Priorität
- dc.l TurboName ; Name der Devices
- dc.l idString ; Zeiger auf Kommentar
- dc.l Init ; Zeiger auf Intallationstabelle
-
- ; Hier stehen die Namen für die Installation
-
- TurboName: TURBONAME
- idString: dc.b 'turbo.device 35.0 (17 Okt 1991)',13,10,0 ; Kommentar
- dosName: dc.b "dos.library",0 ; Name der dos.library
- ds.w 0 ; Auf gerade Adresse
-
- EndCode: ; Ende der Resident-Struktur
-
- Init: ; Installationstabelle
- dc.l TurboDev_SIZE ; Größe der Device-Struktur
- dc.l funcTable ; Funktionstabelle
- dc.l dataTable ; Datentabelle
- dc.l InitRoutine ; Zeiger auf Installationsroutine
-
- funcTable: ; Funktionstabelle
- dc.l Open ; Öffnen des Devices
- dc.l Close ; Schließen des Devices
- dc.l Expunge ; Entfernen des Devices
- dc.l Null ; Unbenutzte Funktion
- dc.l BeginIO ; Kommandohandler
- dc.l AbortIO ; Abbruch einer Funktion
- dc.l CopyMemFast ; Kopierroutine (512 Bytes/Durchlauf)
- dc.l CopyMemSlow ; Kopierroutine (byteweise)
- dc.l CheckUnit ; Unit gültig ?
- dc.l -1 ; Ende der Tabelle
-
- dataTable: ; Datentabelle
- INITBYTE LH_TYPE,NT_DEVICE ; Typ der Tabelle
- INITLONG LN_NAME,TurboName ; Name
- INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED ; Flags
- INITWORD LIB_VERSION,VERSION ; Version
- INITWORD LIB_REVISION,REVISION ; Revision
- INITLONG LIB_IDSTRING,idString ; Kommentar
- dc.l 0 ; Ende der Tabelle
-
- ; ========================================================
- ; = Hier steht die Installationsroutine, die beim ersten =
- ; = Zugriff auf das Device aufgerufen wird, um die Stru- =
- ; = ktur vollständig zu installieren. =
- ; = Ihe Parameter sind: =
- ; = => D0 = Zeiger auf die Device-Struktur =
- ; = => A0 = Zeiger auf die Segmentliste =
- ; = => A6 = Zeiger auf die exec.library =
- ; = =
- ; = <= D0 = Zeiger auf die Device-Struktur =
- ; ========================================================
-
- InitRoutine:
- move.l a5,-(a7) ; a5 retten
- move.l d0,a5 ; Device nach a5
- move.l a6,td_SysLib(a5) ; exec.library in SysLib
- move.l a0,td_SegList(a5) ; Segmentliste in SegList
- lea dosName(pc),a1 ; Name der dos.library
- moveq #0,d0 ; Version=0
- CALLSYS OpenLibrary ; Library öffnen
- move.l d0,td_DosLib(a5) ; dos.library in DosLib
- bne.s Dos_OK ; Konnte Library geöffnet werden ?
- ALERT AG_OpenLib!AO_DOSLib ; Nein, dann Reset
- Dos_OK: ; Ja
- move.b #1,td_DriveNum(a5) ; Start-Namensnummer ist 1
- move.l a5,d0 ; Device nach d0
- move.l (a7)+,a5 ; a5 freigeben
- rts ; Rücksprung
-
- ; =====================================================
- ; = Die Open-Funktion wird immer aufgerufen, wenn ein =
- ; = Programm das Turbo-Device öffnet. Sie installiert =
- ; = die Unit-Struktur. =
- ; = Ihre Parameter sind: =
- ; = => D0 = Unitnummer =
- ; = => D1 = Flags =
- ; = => A1 = Zeiger auf die IOStdReq-Struktur =
- ; = => A6 = Zeiger auf das Device =
- ; =====================================================
-
- Open:
- movem.l d2/a2-a4,-(a7) ; Register retten
- move.l a1,a2 ; IOStdReq nach a2
- moveq #TURBO_NUMUNITS,d2 ; Unitanzahl nach d2
- cmp.l d2,d0 ; Unitnummer gültig ?
- bcc.s Open_error ; Nein, dann springe zu Open_error
- move.l d0,d2 ; Unitnummer nach d2
- lsl.l #2,d0 ; Nummer mit 4 multiplizieren
- lea td_Units(a6,d0.l),a4 ; Unit-Adresse nach a4
- move.l (a4),d0 ; Adresse nach d0
- bne.s Open_ok ; zu Open_ok springen
- bsr InitUnit ; Unit installieren
- move.l (a4),d0 ; Unit nach d0
- beq.s Open_error ; Fehler? Dann springe zum Open_error
- Open_ok: ; Open_ok:
- move.l d0,a3 ; Unit nach a3
- move.l d0,IO_UNIT(a2) ; Unit installieren
- addq.w #1,LIB_OPENCNT(a6) ; Device-Benutzerzähler +1
- addq.w #1,UNIT_OPENCNT(a3) ; Unit-Benutzerzäher +1
- bclr #LIBB_DELEXP,td_Flags(a6) ; Entfernungsflag löschen
- Open_end: ; Open_end:
- movem.l (a7)+,d2/a2-a4 ; Register freigeben
- rts ; Rücksprung
-
- ; Wenn ein Fehler aufgetreten ist, dann wird zu
- ; Open_error gesprungen.
-
- Open_error: ; Open_error:
- move.b #IOERR_OPENFAIL,IO_ERROR(a2) ; Fehler in io_Error
- bra.s Open_end ; Zum Ende springen
-
- ; ========================================================
- ; = Wenn das Device über CloseDevice() geschlossen wird, =
- ; = wird Close aufgerufen. Diese Funktion gibt den =
- ; = Speicher für das Unit frei, wenn Kein Programm mehr =
- ; = auf das Unit zugreift. Wird von keinem Programm mehr =
- ; = auf das Device zugegriffen und ist das LIBB_DELEXP- =
- ; = -Flag gesetzt, dann wird das Device mit Expunge =
- ; = entfernt. =
- ; = Ihre Parameter sind: =
- ; = => A1 = Zeiger auf die IOStdReq-Struktur =
- ; = => Zeiger auf die Device-Struktur =
- ; = =
- ; = <= Zeiger auf die Segmentliste =
- ; ========================================================
-
- Close:
- movem.l a2-a3,-(a7) ; Register retten
- move.l a1,a2 ; IOStdReq nach a2
- move.l IO_UNIT(a2),a3 ; Unit nach a3
- moveq.l #-1,d0 ; Segmentlist=-1
- move.l d0,IO_UNIT(a2) ; Unit=-1
- move.l d0,IO_DEVICE(a2) ; Device=-1
- subq.w #1,UNIT_OPENCNT(a3) ; Unit-Zugriffszähler-1
- bne.s 1$ ; Wenn nicht 0, dann springe zu 1$
- bsr ExpungeUnit ; Springe zu ExpungeUnit
- 1$: ; 1$:
- clr.l d0 ; Segmentliste=0
- subq.w #1,LIB_OPENCNT(a6) ; Device-Zugriffszähler+1
- bne.s Close_end ; Wenn nicht 0, dann Ende
- btst #LIBB_DELEXP,td_Flags(a6) ; Ist LIBB_DELEXP gesetzt ?
- beq.s Close_end ; Nein, dann Close_end
- bsr Expunge ; Springe zu Expunge
- Close_end: ; Close_end:
- movem.l (a7)+,a2-a3 ; Register freigeben
- rts ; Rücksprung
-
- ; =====================================================
- ; = Expunge entfernt das Device und gibt den Speicher =
- ; = wieder frei. =
- ; = Ihre Parameter sind: =
- ; = => A6 = Zeiger auf das Device =
- ; = =
- ; = <= D0 = Zeiger auf die Segmentliste =
- ; =====================================================
-
- Expunge:
- movem.l d2/a5-a6,-(a7) ; Register retten
- move.l a6,a5 ; Device nach a5
- move.l td_SysLib(a5),a6 ; exec.library nach a6
- tst.w LIB_OPENCNT(a5) ; Ist Zugriffszähler=0 ?
- beq 1$ ; Ja, dann springe zu 1$
- bset #LIBB_DELEXP,td_Flags(a5) ; LIBB_DELEXP-Flag löschen
- clr.l d0 ; Segmentliste=0
- bra.s Expunge_end ; Springe zu Expunge_end
- 1$: ; 1$:
- move.l td_SegList(a5),d2 ; SegList nach d2
- move.l a5,a1 ; Device nach a1
- CALLSYS Remove ; Device aus DeviceList entfernen
- move.l td_DosLib(a5),a1 ; dos.library nach a1
- CALLSYS CloseLibrary ; Library schließen
- move.l a5,a1 ; Device nach a1
- clr.l d0 ; d0=0
- move.w LIB_NEGSIZE(a5),d0 ; Negative Größe nach d0
- sub.w d0,a1 ; Negative Größe vom Device abziehen
- add.w LIB_POSSIZE(a5),d0 ; Positive Größe nach d0
- CALLSYS FreeMem ; Speicher freigeben
- move.l d2,d0 ; Segmentliste nach d2
- Expunge_end: movem.l (a7)+,d2/a5-a6 ; Register freigeben
- rts ; Rücksprung
-
- ; Diese Funktion (ExtFuncDev) ist nicht belegt.
-
- Null:
- clr.l d0 ; Rückgabe=0
- rts ; Rücksprung
-
- TURBOPROCSTACK EQU $200 ; Stackgröße
- TURBOPROCPRI EQU 110 ; Priorität
-
- ; ===========================================================
- ; = InitUnit erstellt den neuen Prozeß für die Verwaltungs- =
- ; = einheit und die neue Unit-Struktur. Dem Prozeß wird die =
- ; = Adresse des Devices in einer Message mitgeteilt. Die =
- ; = Message ist in der Unit-Struktur integriert. =
- ; = Ihre Parameter sind: =
- ; = => D2 = Unitnummer =
- ; = => A6 = Zeiger auf Device =
- ; ===========================================================
-
- InitUnit:
- movem.l d2-d4,-(a7) ; Register retten
- move.l #TurboDevUnit_SIZE,d0 ; Unitgröße is d0
- move.l #MEMF_PUBLIC!MEMF_CLEAR,d1 ; Flags in d1
- LINKSYS AllocMem,td_SysLib(a6) ; Speicher belegen
- tst.l d0 ; Konnte Speicher belegt werden ?
- beq InitUnit_end ; Nein,dann Ende
- move.l d0,a3 ; Speicher nach a3
- move.l #0,tdu_Position(a3) ; Lese/Schreibkopf steht auf 0
- movem.l d1-d7/a0-a6,-(sp) ; Register retten
- move.l a3,-(sp) ; Unit auf Stapel
- ext.w d2 ; Unitnummer auf Wortgröße
- ext.l d2 ; Unitnummer auf Langwortgröße
- move.l d2,-(sp) ; Unitnummer auf Stapel
- move.l a6,-(sp) ; Device auf Stapel
- move.l $4,-(sp) ; ExecBase auf Stapel
- jsr _GetMemory ; Speicher organisieren
- add.w #16,sp ; Stapel erhöhen
- movem.l (sp)+,d1-d7/a0-a6 ; Register freigeben
- tst.l d0 ; Konnte Speicher belegt werden ?
- beq InitUnit_end ; Nein, dann Ende
- move.l d0,tdu_Memory(a3) ; Speicher in tdu_Memory
- clr.l tdu_LastComm(a3) ; tdu_LastComm=0
- move.b d2,tdu_UnitNum(a3) ; Unitnummer in UnitNum
- move.l #TURBOPROCSTACK,d4 ; Stack in d4
- move.l #TurboProc_SegList,d3 ; SegList in d3
- lsr.l #2,d3 ; Durch 4 teilen
- moveq #TURBOPROCPRI,d2 ; Priorität in d2
- move.l #TurboName,d1 ; Name in d1
- LINKSYS CreateProc,td_DosLib(a6) ; Prozeß erstellen
- tst.l d0 ; Konnte Prozeß erstellt werden ?
- beq InitUnit_FreeUnit ; Nein, dann Ende
- move.l d0,tdu_Process(a3) ; Prozeß in tdu_Prozeß
- move.l d0,a0 ; Prozeß nach a0
- lea -pr_MsgPort(a0),a0 ; MsgPort abziehen
- move.l a0,MP_SIGTASK(a3) ; Prozeß in MP_SIGTASK
- move.b #PA_IGNORE,MP_FLAGS(a3) ; MP_FLAGS=PA_IGNORE
- lea MP_MSGLIST(a3),a1 ; MsgList nach a1
- NEWLIST a1 ; Neue Liste erstellen
- lea tdu_Msg(a3),a1 ; Message nach a1
- move.l a3,tdm_Unit(a1) ; Unit in tdm_Unit
- move.l a6,tdm_Device(a1) ; Device in tdm_Device
- move.l d0,a0 ; Messageport nach a0
- LINKSYS PutMsg,td_SysLib(a6) ; Message senden
- clr.l d0 ; d0=0
- move.b tdu_UnitNum(a3),d0 ; UnitNum nach d0
- lsl.l #2,d0 ; Mal 4
- move.l a3,td_Units(a6,d0.l) ; Unit in td_Unit
- InitUnit_end: ; Ende:
- movem.l (a7)+,d2-d4 ; Register freigeben
- rts ; Rücksprung
-
- InitUnit_FreeUnit: ; Fehler:
- bsr FreeUnit ; Unit freigeben
- bra.s InitUnit_end ; Zum Ende springen
-
- ; #####################################################
- ; # FreeUnit gibt den Speicher der Unit-Struktur frei #
- ; # Ihr Parameter ist: #
- ; # => A3 = Zeiger auf die Unit-Struktur #
- ; #####################################################
-
- FreeUnit:
- move.l tdu_Memory(a3),a1 ; Speicher in a1
- move.l tdu_Size,d0 ; Größe in d0
- LINKSYS FreeMem,td_SysLib(a6) ; Speicher freigeben
- move.l a3,a1 ; Unit in a3
- move.l #TurboDevUnit_SIZE,d0 ; Unitgröße in d0
- LINKSYS FreeMem,td_SysLib(a6) ; Speicher freigeben
- rts ; Rücksprung
-
- ; #####################################################
- ; # ExpungeUnit entfernt eine Verwaltungseinheit, die #
- ; # nicht mehr benötigt wird. #
- ; # Ihre Parameter sind: #
- ; # => A3 = Zeiger auf Unit-Struktur #
- ; # => A6 = Zeiger auf Device #
- ; #####################################################
-
- ExpungeUnit:
- move.l d2,-(a7) ; d2 retten
- move.l tdu_Process(a3),a1 ; Prozeß nach a1
- lea -pr_MsgPort(a1),a1 ; MsgPort abziehen
- LINKSYS RemTask,td_SysLib(a6) ; Prozeß beenden
- clr.l d2 ; d2=0
- move.b tdu_UnitNum(a3),d2 ; Unitnummer nach d2
- bsr.s FreeUnit ; Unit freigeben
- lsl.l #2,d2 ; Unitnummer mit 4 multiplizieren
- clr.l td_Units(a6,d2.l) ; td_Unit löschen
- move.l (a7)+,d2 ; d2 freigeben
- rts ; Rücksprung
-
- ; =================================================
- ; = cmdtable: =
- ; = Hier stehen die Befehle, die durch das Device =
- ; = aufgerufen werden können. Die Befehle sind =
- ; = der Rehe nach in der Tabelle aufgeführt. =
- ; = Invalid ist der Befehl 0. Die Befehle Reset =
- ; = bis Flush sind Befehle, die im jedem Device =
- ; = vorhanden sind. Die Befehle Reset bis Prot- =
- ; = status müssen bei jedem Laufwerk vorhanden =
- ; = sein, da DOS diese Befehle für die Verwaltung =
- ; = begötigt. Die Direkt-Befehle sind in der =
- ; = Konstante "DirektBefehle" mit oder verknüpft. =
- ; = Alle in dieser Konstante aufgeführten Befehle =
- ; = werden direkt ausgeführt, und nicht an den =
- ; = Prozeß geschickt. =
- ; =================================================
-
- cmdtable:
- ; Hier stehen die Befehle, die alle Devices besitzen.
- ; Die Befehle ab Motor sind für Laufwerke wichtig.
- ; Sie werden vom DOS benutzt und müssen vorhanden
- ; sein.
-
- dc.l Invalid ; Invalid Keine Funktion
- dc.l MyReset ; Reset Keine Funktion
- dc.l Read ; Read Block lesen
- dc.l Write ; Write Block schreiben
- dc.l Update ; Update Buffer schreiben
- dc.l Clear ; Clear Buffer löschen
- dc.l MyStop ; Stop Abarbeitung anhalten
- dc.l Start ; Start Abarbeitung wieder starten
- dc.l Flush ; Flush Alle Messages als Abgebrochen zurücksenden
- dc.l Motor ; Motor Motor ein- und ausschalten
- dc.l Seek ; Seek Schreib/Lesekopf positionieren
- dc.l Write ; Format Track formatieren
- dc.l Remove ; Remove Diskettenwechsel-Interrupt installiern
- dc.l Status ; ChangeNum: Diskettenwechsel (0)
- dc.l Status ; ChangeState: Diskette eingelegt (ja)
- dc.l Status ; ProtStatus: Schreibschutz (aus)
-
- ; Hier beginnen die eigenen Befehle.
- ; Sie sind für die Arbeit des DOS
- ; mit dem Device unwichtig.
-
- dc.l RawRead ; RawRead: Byteweises lesen
- dc.l RawWrite ; RawWrite: Byteweises schreiben
- dc.l GetDriveType ; GetDriveType: Laufwerkstyp (=> 5.25 Zoll)
- dc.l GetNumTracks ; GetNumTracks: Anzahl der Tracks
- dc.l AddChangeInt ; Diskettenwechselinterrupt installieren
- dc.l RemChangeInt ; Diskettenwechselinterrupt entfernen
- dc.l LastComm ; LastComm: Letztes Kommando ermitteln
- cmdtableend:
-
- DirektBefehle equ $1!$2!$10!$20!$40!$80!$100
-
- FUNKANZ: EQU 23 ; 23 Befehle
-
- ; ==========================================================
- ; = BeginIO ist die Funktion, die die Befehle verarbeitet. =
- ; = Sie stellt die gültigkeit fest und bestimmt, ob der =
- ; = Befehl zum Prozeß des Units gesendet oder direkt aus- =
- ; = geführt wird. =
- ; = Ihre Parameter sind: =
- ; = => A1 = Zeiger auf die IOStdReq-Strunktur =
- ; = => A6 = Zeiger auf die Device-Struktur =
- ; ==========================================================
-
- BeginIO:
- move.l a3,-(a7) ; a3 retten
- move.l IO_UNIT(a1),a3 ; Zeiger auf das Unit in a3
- move.w IO_COMMAND(a1),d0 ; Kommando nach d0
- bclr #15,d0 ; Extended-Bit löschen
- cmp.w #FUNKANZ,d0 ; Ist Kommando gültig ?
- bcc BeginIO_NoCmd ; Nein? Dann springe zu BeginIO_NoCmd
- DISABLE a0 ; Interrupts sperren
- move.l #DirektBefehle,d1 ; Ist der Befehl ein Direkt-Befehl ?
- btst d0,d1 ; Ja ?
- bne.s BeginIO_Immediate ; Wenn Nein, dann springe
- BeginIO_QueueMsg: ; Ja.
- bset #UNITB_INTASK,UNIT_FLAGS(a3) ; Unit-Bit setzen
- bclr #IOB_QUICK,IO_FLAGS(a1) ; Quick-Flag löschen
- ENABLE a0 ; Interrupts erlauben
- move.l a3,a0 ; Unit nach a0
- LINKSYS PutMsg,td_SysLib(a6) ; Message Senden
- bra.s BeginIO_end ; Ende
-
- BeginIO_Immediate:
- ENABLE a0 ; Interrupts erlauben
- bsr PerformIO ; Befehl ausführen
- BeginIO_end: move.l (a7)+,a3 ; a3 wieder zurückgeben
- rts ; Rücksprung
-
- BeginIO_NoCmd: ; Kommandofehler
- move.b #IOERR_NOCMD,IO_ERROR(a1) ; Fehler in io_Error
- bra.s BeginIO_end ; Zum Ende springen
-
- ; ===================================================
- ; = PerformIO: =
- ; = Diese Funktion holt die Adresse des Befehls aus =
- ; = der Tabelle und springt zu der angegebenen =
- ; = Adresse. =
- ; = Ihre Parameter sind: =
- ; = => A1 = Zeiger auf IOStdReq =
- ; = => A3 = Zeiger auf Unit-Struktur =
- ; = => A6 = Zeiger auf Device =
- ; ===================================================
-
- PerformIO:
- move.l a2,-(a7) ; a2 retten
- move.l a1,a2 ; IOStdReq nach a2
- move.w IO_COMMAND(a2),d0 ; Kommando nach d0
- lsl.w #2,d0 ; mal 4
- lea cmdtable(pc),a0 ; Kommandoadresse holen
- move.l 00(a0,d0.w),a0 ; Adresse nach a0
- jsr (a0) ; Befehl ausführen
- move.l (a7)+,a2 ; a2 freigeben
- rts
-
- ; ====================================================
- ; = TermIO wird zur Beendigung von jeder Funktion =
- ; = aufgerufen. Sie sendet, wenn der Befehl über den =
- ; = Prozeß lief, die Message zurück. =
- ; ====================================================
-
- TermIO:
- move.w IO_COMMAND(a1),d0 ; Kommando nach d0
- move.w d0,d5 ; und d5
- ext.l d5 ; auf Langwortgröße erweiten
- move.l d5,tdu_LastComm(a3) ; Kommando in tdu_LastComm
- move.l #DirektBefehle,d1 ; Direktbefehlsmaske in d1
- btst d0,d1 ; Direktbefehl ?
- bne.s TermIO_Direkt ; Ja
- btst #UNITB_INTASK,UNIT_FLAGS(a3) ; Ging der Befehl über den Prozeß ?
- bne.s TermIO_Direkt ; Nein
- bclr #UNITB_ACTIVE,UNIT_FLAGS(a3) ; Task freigeben
- TermIO_Direkt:
- btst #IOB_QUICK,IO_FLAGS(a1) ; Quick-Flag gesetzt ?
- bne.s TermIO_end ; Nein, dann springe
- LINKSYS ReplyMsg,td_SysLib(a6) ; Message zurücksenden
- TermIO_end: rts ; Rücksprung
-
- ; Diese Routine ist zum Abbrechen eines laufenden Befehls
- ; gedacht. Da das Abbrechen eines Befehls in Laufwerken
- ; ist nicht sinnvoll ist, ist eine Abbruchfunktion nicht
- ; implementiert.
-
- AbortIO: ; Funktion zum Abbruch eines Kommandos
- moveq #0,d0 ; Kein Fehler
- rts ; Rücksprung
-
- CheckUnit: ; Unit belegt ?
- lsl.l #2,d0 ; Nummer*4
- lea td_Units(a6,d0.l),a0 ; Unit nach a0
- move.l (a0),d0 ; a0 in d0
- rts ; Rücksprung
-
- ; ================================================
- ; = Hier beginnen die Device-Befehle, die durch =
- ; = den vorher installierten Prozeß oder durch =
- ; = BeginIO angesprungen werden. =
- ; = Alle Befehle müssen mit TermIO abgeschlossen =
- ; = werden! =
- ; = Die Parameter sind: =
- ; = => A1 = Zeiger auf die IOStdReq-Struktur =
- ; = => A3 = Zeiger auf die Unit-Struktur =
- ; = => A6 = Zeiger auf die Device-Struktur =
- ; ================================================
-
- MyReset:
- Invalid: ; Abarbeitung eines ungültigen Befehls
- move.b #IOERR_NOCMD,IO_ERROR(a1) ; IOERR_NOCMD nach io_Error
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- GetDriveType: ; Laufwerkstyp ermitteln
- move.l #2,IO_ACTUAL(a1) ; In einem Ram-Laufwerk gibt es keine
- bsr TermIO ; Typen! Rückgabe als 5.25 Zoll.
- rts
-
- GetNumTracks: ; Anzahl der Tracks ermitteln
- move.l tdu_NumTracks(a3),IO_ACTUAL(a1) ; Größe in Actual
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- LastComm: ; Letzten Kommando ermitteln
- move.l tdu_LastComm(a3),IO_ACTUAL(a1) ; Kommando in Actual
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- RawRead: ; Byteweises lesen
- movem.l a0/a2/d0,-(sp) ; Register retten
- move.l tdu_Memory(a3),a0 ; Speicher in a0
- add.l IO_OFFSET(a1),a0 ; Offset addieren
- move.l IO_DATA(a1),a2 ; Daten in a2
- move.l IO_LENGTH(a1),d0 ; Lange in d0
- jsr CopyMemSlow
- movem.l (sp)+,a0/a2/d0 ; Register freigeben
- move.l IO_LENGTH(a1),IO_ACTUAL(a1); Länge in Actual
- move.l IO_OFFSET(a1),tdu_Position(a3) ; Lesekopfposition
- clr.b IO_ERROR(a1) ; Keine Fehler
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- RawWrite: ; Byteweises lesen
- movem.l a0/a2/d0,-(sp) ; Register retten
- move.l tdu_Memory(a3),a2 ; Speicher in a2
- add.l IO_OFFSET(a1),a2 ; Offset addieren
- move.l IO_DATA(a1),a0 ; Daten in a0
- move.l IO_LENGTH(a1),d0 ; Länge in d0
- jsr CopyMemSlow ; Speicher kopieren
- movem.l (sp)+,a0/a2/d0 ; Register freigeben
- move.l IO_LENGTH(a1),IO_ACTUAL(a1); Länge in Actual
- move.l IO_OFFSET(a1),tdu_Position(a3) ; Schreibkopfposition
- clr.b IO_ERROR(a1) ; Keine Fehler
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- Read: ; Block lesen
- movem.l a0/a2/d0,-(sp) ; Register retten
- move.l tdu_Memory(a3),a0 ; Speicher in a0
- add.l IO_OFFSET(a1),a0 ; Offset addieren
- move.l IO_DATA(a1),a2 ; Daten in a2
- move.l IO_LENGTH(a1),d0 ; Länge in d0
- jsr CopyMemFast ; Zur Kopierroutine springen
- movem.l (sp)+,a0/a2/d0 ; Register freigeben
- move.l IO_LENGTH(a1),IO_ACTUAL(a1); Länge in Actual
- move.l IO_OFFSET(a1),tdu_Position(a3) ; Lesekopfposition
- clr.b IO_ERROR(a1) ; Keine Fehler
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- Write: ; Block schreiben
- movem.l a0/a2/d0,-(sp) ; Register retten
- move.l tdu_Memory(a3),a2 ; Speicher in a2
- add.l IO_OFFSET(a1),a2 ; Offset addieren
- move.l IO_DATA(a1),a0 ; Daten in a0
- move.l IO_LENGTH(a1),d0 ; Länge in d0
- jsr CopyMemFast ; Zur Kopierroutine springen
- movem.l (sp)+,a0/a2/d0 ; Register freigeben
- move.l IO_LENGTH(a1),IO_ACTUAL(a1); Länge in Actual
- move.l IO_OFFSET(a1),tdu_Position(a3) ; Schreibkopfposition
- clr.b IO_ERROR(a1) ; Keine Fehler
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- ; ================================================
- ; = CopyMemSlow: =
- ; = Diese Routine kopiert den Speicher für die =
- ; = Raw-Befehle. Sie kopiert byteweise und ist =
- ; = deshalb auch langsamer. =
- ; = Ihre Parameter sind: =
- ; = => D0 = Länge =
- ; = => A0 = Quelladresse =
- ; = => A2 = Zieladresse =
- ; ================================================
-
- CopyMemSlow: ; Speicher Byteweise kopieren
- tst.l d0 ; Ist etwas zu kopieren ?
- beq CopyMemSlow_Ende ; Nein, dann Ende
- CopyMemSlow_Loop: ; Schleife
- move.b (a0)+,(a2)+ ; a0 nach a2 und erhöhen
- dbra d0,CopyMemSlow_Loop ; Zurückzählen
- CopyMemSlow_Ende: ; Ende
- rts ; Rücksprung
-
- ; ================================================
- ; = CopyMemFast: =
- ; = Diese Routine ist das Kernstück des Devices. =
- ; = Über sie werden alle Scheib -und Lesebefehle =
- ; = abgewickelt. Sie kopiert 512 Bytes in einem =
- ; = Durchlauf! =
- ; = RawRead und RawWrite laufen nicht über diese =
- ; = Funktion, weil sie auch einzelne Bytes lesen =
- ; = können. Sie sind dadurch langsamer. =
- ; = Ihre Parameter sind: =
- ; = => D0 = Länge =
- ; = => A0 = Quelladresse =
- ; = => A2 = Zieladresse =
- ; ================================================
-
- ; INIT_COPY ist ein Macro, um die Routine zu installieren.
- ; Es wird 8 mal aufgerufen, um 128 befehle zu installieren.
-
- INIT_COPY: MACRO
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- move.l (a0)+,(a2)+
- endm
-
- CopyMemFast:
- tst.l d0 ; Ist etwas zu kopieren ?
- beq CopyMemFast_Ende ; Nein, dann springe zum Ende
- lsr.l #7,d0 ; Länge durch 128 dividieren
- lsr.l #2,d0 ; Länge durch 4 dividieren
- subq.l #1,d0 ; 1 subtrahieren
- CopyMemFast_Loop: ; Kopierschleife
- INIT_COPY
- INIT_COPY
- INIT_COPY
- INIT_COPY
- INIT_COPY
- INIT_COPY
- INIT_COPY
- INIT_COPY
- dbra d0,CopyMemFast_Loop ; Zurückzählen
- CopyMemFast_Ende: ; Ende:
- rts ; Rücksprung
-
- MyStop: ; Ausführung anhalten
- bset #TDUB_STOPPED,UNIT_FLAGS(a3) ; Flag setzen
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- Start: ; Ausführung weiterführen
- bsr InternalStart ; Zu InternalStart springen
- move.l a2,a1 ; IOStdReq nach a1
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- InternalStart: ; Startroutine:
- bclr #TDUB_STOPPED,UNIT_FLAGS(a3) ; Stop-Flag löschen
- move.l MP_SIGTASK(a3),a1 ; Task nach a1
- clr.l d0 ; d0=0
- move.b MP_SIGBIT(a3),d1 ; Signalbit nach d1
- bset d1,d0 ; Bit setzen
- LINKSYS Signal,td_SysLib(a6) ; Signal setzen
- rts ; Rücksprung
-
- Flush: ; Alle Befehle als Abgebrochen zurück
- movem.l d2/a6,-(a7) ; Register retten
- move.l td_SysLib(a6),a6 ; ExecBase nach a6
- FORBID
- Flush_Loop: ; Schleife:
- move.l a3,a0 ; Unit nach a0
- CALLSYS GetMsg ; Message holen
- tst.l d0 ; Message angekommen ?
- beq.s Flush_end ; Nein, dann Ende
- move.l d0,a1 ; IOStdReq nach a1
- move.b #IOERR_ABORTED,IO_ERROR(a1); Fehler nach io_Error
- CALLSYS ReplyMsg ; Message zurückschicken
- bra.s Flush_Loop ; Zu Schleife springen
- Flush_end: PERMIT
- movem.l (a7)+,d2/a6 ; Register freigeben
- move.l a2,a1 ; IOStdReq nach a1
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- Seek: ; Schreib/Lesekopf positionieren
- move.l IO_OFFSET(a1),tdu_Position(a3) ; Position eintragen
- AddChangeInt: ; Der Seek-Befehl endet wie die
- RemChangeInt: ; folgenden Befehle.
- Update: ; Nicht gültige Befehle, die jedoch
- Clear: ; keinen Fehler zurückgeben dürfen, da
- Remove: ; diese von DOS aufgerufen werden,
- clr.b IO_ERROR(a1) ; weil sie bei einem Disketten-
- bsr TermIO ; laufwerk eine Bestimmte Funktion
- rts ; haben.
-
- Motor: ; Motor ein- und Ausschalten
- move.l IO_LENGTH(a1),d0 ; Da Ram-Disks keine Motoren
- cmp.l #1,d0 ; besitzen wird hier auch
- beq 1$ ; nichts ausgeschaltet.
- move.l #1,d0 ; DOS verlangt in Actual den
- bra 2$ ; vorherigen Status des Motors.
- 1$: ; Es wird der Gegenteilige
- move.l #0,d0 ; Status aus io_Length in
- 2$: ; io_Actual übergeben.
- move.l d0,IO_ACTUAL(a1) ; Alter Status in Actual
- clr.b IO_ERROR(a1) ; Kein Fehler
- bsr TermIO ; Zu TermIO springen
- rts ; Rücksprung
-
- Status: ; Anzahl der Diskettenwechsel
- move.l #0,IO_ACTUAL(a1) ; Diskette Schreibgeschützt ?
- move.b #0,IO_ERROR(a1) ; Diskette eingelegt ?
- bsr TermIO ; Da alle Befehle in einer Ram-Disk 0
- rts ; ergeben, wird nur eine Routine benötigt.
-
- ; ==========================================================================
-
- ; Hier beginnen die Routinen für die Prozesse.
- ; Der Funktion CreateProc wird ein Zeiger auf TurboProc_SegList
- ; übergeben. Als erster Befehl in der SegList muß "dc.l 0" stehen,
- ; weil an dieser Stelle ein Zeiger auf das nächste Segment erwartet wird!
-
- CNOP 0,4 ; Auf Langwortgröße erweitern
- TurboProc_SegList: ; Anfang der SegList
- dc.l 0 ; Zeiger auf nächstes Segment (=NULL)
-
- Proc_Begin: ; Code der SegList
- move.l $4,a6 ; ExecBase nach a6
- sub.l a1,a1 ; a1=NULL
- CALLSYS FindTask ; Task suchen
- move.l d0,a0 ; Task nach a0
- move.l d0,a4 ; und a4
- lea pr_MsgPort(a0),a0 ; der MsgPort von a0 nach a0
- CALLSYS WaitPort ; Auf Nachricht warten
- move.l d0,a1 ; Nachricht in a1
- move.l d0,a2 ; und a2
- CALLSYS Remove ; Nachricht löschen
- move.l tdm_Device(a2),a5 ; Device nach a5
- move.l tdm_Unit(a2),a3 ; Unit nach a3
- moveq #-1,d0 ; -1 nach d0
- CALLSYS AllocSignal ; Freies Signal holen
- move.b d0,MP_SIGBIT(a3) ; Signal in SigBit
- move.b #PA_SIGNAL,MP_FLAGS(a3) ; Flags = PA_SIGNAL
- clr.l d7 ; d7=0
- bset d0,d7 ; Signal in d7 setzen
- bra.s Proc_CheckStatus ; Zu Proc_CheckStatus springen
-
- Proc_MainLoop: ; Hauptschleife
- move.l d7,d0 ; Signal nach d7
- CALLSYS Wait ; Auf Signal warten
- Proc_CheckStatus: ; Proc_CheckStatus:
- btst #TDUB_STOPPED,UNIT_FLAGS(a3) ; Ist Stop-Flag gesetzt ?
- bne.s Proc_MainLoop ; Ja, dann zur Hauptschleife
- bset #UNITB_ACTIVE,UNIT_FLAGS(a3) ; Ist Task aktiv ?
- bne.s Proc_MainLoop ; Ja, dann warten, bis Task frei wird
-
- Proc_NextMsg:
- move.l a3,a0 ; Zeiger auf Port in a0
- CALLSYS GetMsg ; Auf Message warten
- tst.l d0 ; Message angekommen ?
- beq.s Proc_Unlock ; Nein, dann springe
- move.l d0,a1 ; Message nach a1
- exg a5,a6 ; a5 mit a6 vertauschen
- bsr PerformIO ; Befehl auswerten
- exg a5,a6 ; a5 mit a6 vertauschen
- bra Proc_NextMsg ; Nächste Message bearbeiten
-
- Proc_Unlock:
- bclr #UNITB_ACTIVE,UNIT_FLAGS(a3) ; Aktive-Bit löschen
- bclr #UNITB_INTASK,UNIT_FLAGS(a3) ; Intask-Bit löschen
- bra Proc_MainLoop ; Zur Hauptschleife springen
-
- END
-
-